Inicio

Importar as bibliotecas

In [873]:
import datetime
from datetime import datetime
import traceback 
import os
import getpass
import textwrap

# Conexao às bases de dados
import pyodbc 
#import pymssql
import sqlalchemy
from sqlalchemy import create_engine

# Analise
import pandas as pd 
import numpy as np 

#Visualization
import matplotlib
import matplotlib.pyplot as plt 
%matplotlib inline
import seaborn as sns 
import plotly
import plotly.express as px

Configurações

In [2]:
import warnings 
warnings.filterwarnings("ignore")

class color:
    PURPLE = '\033[95m'
    CYAN = '\033[96m'
    DARKCYAN = '\033[36m'
    BLUE = '\033[94m'
    GREEN = '\033[92m'
    YELLOW = '\033[93m'
    RED = '\033[91m'
    BOLD = '\033[1m'
    UNDERLINE = '\033[4m'
    END = '\033[0m'
#print(color.BOLD + 'Hello World !' + color.END)

Parâmetros

In [3]:
pd.options.display.max_rows = 999
pd.options.display.max_columns = 200
pd.set_option('max_colwidth', 1000) # tamanho das colunas para exibição do conteúdo de textos longos

np.set_printoptions(threshold=1000)

# Formatar numeros float (2 casas decimais)
pd.set_option('display.float_format', lambda x: '%.2f' % x)
pd.set_option('display.float_format', lambda x: '{:.2f}'.format(x))

# Formatações para gráficos
sns.set(style="darkgrid") #cor da area dos plots
figsize = (10,10)

random_state = 123
In [671]:
fig = px.colors.qualitative.swatches()
fig.show()

Definição de Funções

Função remove_spaces

Para um determinado dataframe, elimina-se espaços à direita e esquerda das palavras.

In [5]:
def remove_space (df):
    for col in df.select_dtypes(include = ["object"]).columns:
        df[col] = df[col].str.strip()

Função checar_df

Para um determinado dataframe, são verificados:

  • total de registros;
  • quantidade e tipos de colunas;
  • quantidade de valores únicos;
  • quantidade de valores nulos (para identificar a necessidade de pre processamento dos dados).
In [6]:
def checar_df(df):
    print(color.BOLD  + color.RED + 'Informações do dataframe: ' + color.END)
    df.info()
    
    print(color.BOLD + color.RED + "\nNúmero de observacoes na base de dados: " + color.END, df.shape[0])
    print('Total de ', df.shape[1], 'Colunas: ', df.columns.values.tolist())
    
    print(color.BOLD + color.RED + "\nNúmero de valores unicos (Não inclui NaN): " + color.END)
    display(df.nunique(dropna=True).to_frame(name='Contagem Unicos').sort_index())
    
    print(color.BOLD + color.RED + "Número de valores nulos:" + color.END)
    display(df.isnull().sum().sort_values(ascending=False).to_frame(name='Contagem Nulos').sort_index())

Função checar_val_colunas_df_lista

Para uma determinada lista de valores, são verificadas:

  • valores únicos das colunas de interesse (para identificar as categorias).

Os parâmetros de entrada para a função são:

  • nome do dataframe;
  • a lista de colunas para as quais se deseja obter os valores únicos existentes.
In [7]:
# passar como parâmetro a lista de colunas para as quais se deseja obter os valores únicos existentes
def checar_val_colunas_df_lista(df, lista_colunas):
    print(color.BOLD + color.RED + "Contagem de valores unicos (inclui NaN) e apresentação da lista de valores:  \n"  
      + color.END)
    for column in lista_colunas:
        print(column, ': ', len(df[column].unique()),'valores únicos \n',
              df[column].sort_values().unique().tolist(), '\n')

Função checar_val_colunas_df_nunique

Para uma determinada lista de valores, são verificadas:

  • valores únicos das colunas de interesse (para identificar as categorias).

Os parâmetros de entrada para a função são:

  • nome do dataframe;
  • o número máximo de valores únicos que a coluna possui (ex. mostrar colunas com até 15 valores únicos).
In [8]:
# passar como parâmetro o número máximo de valores únicos (n_unique)
# Ex. mostrar colunas e seus valores únicos apenas quando a coluna tem até N valores únicos
def checar_val_colunas_df_nunique(df, n_unique):
    df_count_unique = df.nunique(dropna=True).to_frame(name='Contagem Unicos').sort_values(by='Contagem Unicos')
    lista_colunas = df_count_unique[df_count_unique['Contagem Unicos'] <= n_unique].index
    
    print(color.BOLD + color.RED + "Contagem de valores unicos (inclui NaN) e apresentação da lista de valores: "  
      + color.END)
    print(color.BOLD + color.RED + '(até', n_unique, 'valores únicos)\n' + color.END)
    for column in lista_colunas:
        print(column, ': ', len(df[column].unique()),'valores únicos \n',
              df[column].sort_values().unique().tolist(), '\n')

Função checar_dois_dataframes

Checa dois dataframes e imprime quais as colunas de um dataframe que não estão em outro dataframe.

In [9]:
def get_df_name(df):
    name =[x for x in globals() if globals()[x] is df][0]
    return name
In [10]:
def compara_dois_dataframes(df1, df2):
    
    df1_col = df1.columns.values
    df2_col = df2.columns.values

    print(color.BOLD + 'Colunas inexistentes no',  str(get_df_name(df1)) + color.END)
    display([c2 for c2 in df2_col if c2 not in df1_col])
    
    print(color.BOLD + 'Colunas inexistentes no' , str(get_df_name(df2)) + color.END)
    display([c1 for c1 in df1_col if c1 not in df2_col])

Função oper_info_resumidas

Dado um dataframe, imprime um resumo das operações, valores contratados, períodos contemplados, entre outras informações.

In [11]:
def oper_info_resumidas(df):
    tipo_oper = df['tipo_oper'].unique()[0]
    
    print('Total de registros de Operações Contratadas na Forma %s: %d operações' % (tipo_oper, df.shape[0]))
    print('   - Forma DIRETA: ', df[df['forma_de_apoio']=='DIRETA'].shape[0])
    print('   - Forma INDIRETA: ', df[df['forma_de_apoio']=='INDIRETA'].shape[0])
    
    print('\nTotal Valor Contratado (em R$ bilhões):',round(df['valor_contratado_reais'].sum()/1000000000,2))
    print('Total Valor Desembolsado (em R$ bilhões):' ,round(df['valor_desembolsado_reais'].sum()/1000000000,2))
    
    print(len(df['numero_do_contrato'].unique()), 'Contratos no período: ', \
      np.min(df['data_da_contratacao']).date(), 'a', \
      np.max(df['data_da_contratacao']).date())
    
    print('Total de', len(df['municipio_codigo'].unique()),'municipios contemplados em',\
                  len(df['uf'].unique()),'estados.')

Função boxplot_vlr_contr_hue

Dado um dataframe e a coluna de interesse (hue), cria um boxplot dos valores contratados quebrados pelo parâmetro "hue".
Por ex. Caso o hue seja forma de apoio (DIRETA/ INDIRETA), haverá boxes para cada possível valor do "hue".

In [12]:
def boxplot_vlr_contr_hue(df, hue, palette):
    f, axes = plt.subplots(1, 1,  figsize=(20, 12))
    g = sns.boxplot(x='ano_contratacao', y='valor_contratado_log', hue=hue, data=df, palette=palette)
    g.axhline(9.5, linestyle='--', linewidth = 1.5, color='r', label='Maiores outliers')

    major_ticks = np.arange(0, 12, 1)
    minor_ticks = np.arange(0, 12, 0.5)
    axes.set_yticks(major_ticks)
    axes.set_yticks(minor_ticks, minor=True)
    axes.grid(which='both', axis='y')

    xlocs, xlabels = plt.xticks()
    ylocs, ylabels = plt.yticks()
    plt.setp(xlabels, fontsize=16, rotation=90)
    plt.setp(ylabels, fontsize=16)
    axes.set(xlabel=''); 
    axes.set_ylabel('Valor Contratado (log)', fontsize=16) 

    axes.set_title('Valores Contratados (log) por Ano e %s' %hue, fontsize=20)
    axes.legend(fontsize=16)

    plt.show()

Axis são definidos automaticamente na função abaixo.

In [13]:
def boxplot_vlr_contr_hue_axis(df, hue, palette):
    f, axes = plt.subplots(1, 1,  figsize=(20, 12))
    g = sns.boxplot(x='ano_contratacao', y='valor_contratado_log', hue=hue, data=df, palette=palette)
    g.axhline(9.5, linestyle='--', linewidth = 1.5, color='r', label='Maiores outliers')

    #major_ticks = np.arange(0, 12, 1)
    #minor_ticks = np.arange(0, 12, 0.5)
    #axes.set_yticks(major_ticks)
    #axes.set_yticks(minor_ticks, minor=True)
    #axes.grid(which='both', axis='y')

    xlocs, xlabels = plt.xticks()
    ylocs, ylabels = plt.yticks()
    plt.setp(xlabels, fontsize=16, rotation=90)
    plt.setp(ylabels, fontsize=16)
    axes.set(xlabel=''); 
    axes.set_ylabel('Valor Contratado (log)', fontsize=16) 

    axes.set_title('Valores Contratados (log) por Ano e %s' %hue, fontsize=20)
    axes.legend(fontsize=16)

    plt.show()

Função plot_val_contr_oper_apoio

Dado um dataframe consolidado (operações automaticas e não automaticas), gera gráfico com a distribuição dos valores contratados conforme o tipo de operação (Automática/ Não Automática) e a forma de apoio (Direta/Indireta), ao longo dos anos.

Foi utilizado o dataframe consolidado pois não há a forma Indireta para as Operações Automáticas.

In [14]:
def plot_val_contr_oper_apoio(df_consol):

    t_vlr_forma_apoio = df_consol.groupby(['ano_contratacao','Oper_Apoio'])['valor_contratado_reais'].sum()/1000000
    t_vlr_forma_apoio = t_vlr_forma_apoio.reset_index() # em milhoes

    #print(color.BOLD + color.BLUE + 'Valores Contratados (em milhões) por Operação e Forma de apoio '+ color.END)
    #print(color.BOLD + color.BLUE + 75*'*' + color.END)
    # display(t_vlr_forma_apoio) # tabela com os valores para cada Oper_apoio, por Ano

    fig = px.bar(t_vlr_forma_apoio.sort_values(by='ano_contratacao', ascending=True),
                 x='ano_contratacao', y='valor_contratado_reais', color='Oper_Apoio',
                 color_discrete_sequence=px.colors.qualitative.Dark2,
                 barmode = 'group', width=900, height=600)
    
    fig.update_layout(title={'text': "Valores Contratados por Tipo de Operação e Forma de apoio",
                             'y':0.95, 'x':0.5, 'xanchor': 'center', 'yanchor': 'top'},
                      yaxis=dict(title='Valor Contratado (milhões)', titlefont_size=14,tickfont_size=14),
                      xaxis=dict(title=''),
                      legend=dict(x=0.05,y=0.9))
    
    fig2 = px.line(t_vlr_forma_apoio.sort_values(by='ano_contratacao', ascending=True),
                 x='ano_contratacao', y='valor_contratado_reais', color='Oper_Apoio',
                 color_discrete_sequence=px.colors.qualitative.Dark2,
                  width=900, height=600)
    
    fig2.update_layout(title={'text': "Valores Contratados por Tipo de Operação e Forma de apoio",
                             'y':0.95, 'x':0.5, 'xanchor': 'center', 'yanchor': 'top'},
                      yaxis=dict(title='Valor Contratado (milhões)', titlefont_size=14,tickfont_size=14),
                      xaxis=dict(title=''),
                      legend=dict(x=0.05,y=0.9))

    fig.update_xaxes(nticks=20, tickangle = 45); fig2.update_xaxes(nticks=20, tickangle = 45) # 20 anos
        
    fig.show(); fig2.show()

Função plot_evol_val_contr_desemb

Dado um dataframe, gera gráfico com a evolução dos valores contratados/ desembolsados ao longo dos anos.

In [15]:
def plot_evol_val_contr_desemb(df):
    tipo_oper = df['tipo_oper'].unique()[0]
    
    # Valor total dos contratos por ano
    t_vlr_contr_ano = df.groupby(['ano_contratacao'])['valor_contratado_reais'].sum()/1000000000 # em bilhoes
    t_vlr_desemb_ano = df.groupby(['ano_contratacao'])['valor_desembolsado_reais'].sum()/1000000000 # em bilhoes

    # Calcula a Taxa de crescimento do Valor total dos contratos (de um ano a outro)
    tx = []
    tx.append(0)
    list = t_vlr_contr_ano.sort_index(ascending=True).values
    for i in range(t_vlr_contr_ano.shape[0]-1):
        dif = np.round((list[i+1] - list[i]) / list[i] * 100,2)
        tx.append(dif)

    tx_d = []
    tx_d.append(0)
    list = t_vlr_desemb_ano.sort_index(ascending=True).values
    for i in range(t_vlr_desemb_ano.shape[0]-1):
        dif = np.round((list[i+1] - list[i]) / list[i] * 100,2)
        tx_d.append(dif)    

    total_vlr_contr_ano = pd.DataFrame({'Total Valor Contratado' : t_vlr_contr_ano, 'Taxa Contr(%)' : tx})\
                                                                    .reset_index()
    total_vlr_desemb_ano = pd.DataFrame({'Total Valor Desembolsado' : t_vlr_desemb_ano, 'Taxa Desemb(%)' : tx_d})\
                                                                    .reset_index()
    total_vlres = pd.merge(left=total_vlr_contr_ano, right=total_vlr_desemb_ano, 
                           how='inner', 
                           on=['ano_contratacao'])

    #display(total_vlr_contr_ano)

    # Setar intervalo para x axis
    ano_min = np.min(total_vlr_contr_ano['ano_contratacao']) 
    ano_max = np.max(total_vlr_contr_ano['ano_contratacao'])

    # Grafico
    fig = plt.figure(figsize = (18,10))
    sns.lineplot(x='ano_contratacao', y='Total Valor Contratado', 
                 data=total_vlres, color ='g', linewidth=2.5, label='Valor Contratado')
    sns.lineplot(x='ano_contratacao', y='Total Valor Desembolsado', 
                 data=total_vlres, color ='b', linewidth=1.5, label='Valor Desembolsado', linestyle='--')

    # Configuracoes
    ax = plt.gca()
    ax.set_title("Operações do Tipo %s: Total dos Valores Contratados/Desembolsados por Ano" % tipo_oper, fontsize=15)
    ax.set(xlabel=''), 
    ax.set_ylabel('Total (em bilhões)', fontsize=16)
    
    max_y = np.max(df.groupby(['ano_contratacao'])['valor_contratado_reais'].sum()/1000000000)
    max_y = round(max_y*1.1,0)
    max_y
    
    major_yticks = np.arange(0, max_y, 5); ax.set_yticks(major_yticks)
    ax.tick_params(axis='x', labelsize=14); ax.tick_params(axis='y', labelsize=14)
    plt.xticks(np.arange(ano_min, ano_max+1, 1))
    ax.legend(fontsize=14)

    plt.show()    

Função stats_tot_mun_uf

Identifica o Total de municípios existentes nas UFs presentes no dataframe.

In [16]:
# Total de Municipios investidos por UF
def stats_tot_mun_uf1(df):
    print('Total de Municipios: ', len(df['municipio_codigo'].unique()), 'Municípios')
    print('Total de Municípios por Estado: ')
    display(
        df[['uf','municipio_codigo']].drop_duplicates().groupby('uf')['municipio_codigo'].count()\
                            .sort_values(ascending=False).reset_index())

Identifica o Total de municípios existentes nas UFs presentes no dataframe, comparando-se com o total de municipios do IBGE.

In [17]:
# Total de Municipios existentes/ investidos por UF
def stats_tot_mun_uf(df):
    print('Total de Municipios IBGE: ', len(ibge['COD_IBGE'].unique()), 'Municípios')
    print('Total de Municipios investidos: ', len(df['municipio_codigo'].unique()), 'Municípios')
    
    df_plot = df[['uf','municipio_codigo']].drop_duplicates().groupby('uf')['municipio_codigo'].count()\
                            .sort_values(ascending=False).reset_index()
    df_plot.columns=['uf','Total Municipios investidos']
   
    df_ibge = ibge.groupby(['SIGLA_UF'])['COD_IBGE'].count().reset_index()
    df_ibge.columns=['uf','Total Municipios IBGE']

    #Juntar info de municipios investidos e total de municipios existentes conforme IBGE
    df_munic = pd.merge(df_plot, df_ibge, on='uf', how='inner')
    df_munic2 = df_munic.melt(id_vars='uf').rename(columns=str.title)
        
    f, axes = plt.subplots(1, 1, figsize = (18,10))
    g = sns.barplot(x='Uf', y='Value', hue='Variable', data=df_munic2.sort_values(by='Value', ascending=False))
    
    axes.set_title('Total de Municipios com investimentos - por UF', fontsize=16)
    axes.set(xlabel='')
    axes.set_ylabel('Total de municipios', fontsize=16)
    
    xlocs, xlabels = plt.xticks()
    plt.setp(xlabels, fontsize=13, rotation=0)
    
    axes.legend(fontsize=16)
    
    #print('Total de Municípios por Estado: ')
    #display(df_munic2)

Carga de dados (csv)

Operações Automáticas

Ações:

  • Carga do csv em dataframe df_auto
  • Formatação de campos
  • Visualização de uma amostra de linhas
In [18]:
%%time
df_auto = pd.read_csv('Operacoes_indiretas_automaticas.csv', sep=';',  decimal=',', 
                       parse_dates=['data_da_contratacao'],
                       low_memory=False)

df_auto['data_da_contratacao'] = pd.to_datetime(df_auto['data_da_contratacao'], format='%Y-%m-%d')

columns_object = ['municipio_codigo']
for c in columns_object:
    df_auto[c] = df_auto[c].astype(int).astype(str)
Wall time: 23.2 s

Operações Não automáticas

Ações:

  • Carga do csv em dataframe df_nauto
  • Formatação de campos
  • Visualização de uma amostra de linhas
In [19]:
%%time
df_nauto = pd.read_csv('Operacoes_nao_automaticas.csv', sep=';',  decimal=',', 
                       parse_dates=['data_da_contratacao'],
                       low_memory=False)

df_nauto['data_da_contratacao'] = pd.to_datetime(df_nauto['data_da_contratacao'], format='%Y-%m-%d')

columns_object = ['municipio_codigo','numero_do_contrato']
for c in columns_object:
    df_nauto[c] = df_nauto[c].astype(int).astype(str)
    
#df_nauto.sample(3).T
Wall time: 295 ms

Base IBGE - Municipios

In [20]:
list_col_string = ['COD_IBGE','COD_SIAFI','COD_UE_TSE_2016','CAPITAL'] 
dict_dtype = {column : 'str'  for column in list_col_string}

ibge = pd.read_csv('ibge.csv', sep=';', dtype = dict_dtype, low_memory=False)
ibge.info()
ibge.head(5).T
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 5570 entries, 0 to 5569
Data columns (total 13 columns):
 #   Column             Non-Null Count  Dtype  
---  ------             --------------  -----  
 0   COD_IBGE           5570 non-null   object 
 1   COD_SIAFI          5569 non-null   object 
 2   NOME_MUNICIPIO     5570 non-null   object 
 3   Nome_Simplificado  5570 non-null   object 
 4   SIGLA_UF           5570 non-null   object 
 5   NOME_UF            5570 non-null   object 
 6   LAT                5570 non-null   float64
 7   LNG                5570 non-null   float64
 8   POP2013            5570 non-null   int64  
 9   CAPITAL            5570 non-null   object 
 10  ALT                5570 non-null   float64
 11  REGIAO             5570 non-null   object 
 12  COD_UE_TSE_2016    5568 non-null   object 
dtypes: float64(3), int64(1), object(9)
memory usage: 565.8+ KB
Out[20]:
0 1 2 3 4
COD_IBGE 1100015 1100023 1100031 1100049 1100056
COD_SIAFI 0033 0007 0037 0009 0027
NOME_MUNICIPIO Alta Floresta D'Oeste Ariquemes Cabixi Cacoal Cerejeiras
Nome_Simplificado ALTA FLORESTA DOESTE ARIQUEMES CABIXI CACOAL CEREJEIRAS
SIGLA_UF RO RO RO RO RO
NOME_UF Rondônia Rondônia Rondônia Rondônia Rondônia
LAT -11.94 -9.91 -13.50 -11.43 -13.20
LNG -62.00 -63.03 -60.54 -61.44 -60.82
POP2013 25728 101269 6495 85863 18041
CAPITAL 0 0 0 0 0
ALT 337.74 138.69 236.06 177.45 262.81
REGIAO N N N N N
COD_UE_TSE_2016 00310 00078 00450 00094 00272

Tratamento de dados

Remoção de espaços (leading/ trailing)

In [21]:
remove_space(df_nauto)
remove_space(df_auto)

Exclusão de campos irrelevantes

Campos com somente um valor são descartados do dataframe.

In [22]:
checar_val_colunas_df_nunique(df_nauto, 1)
del df_nauto['tipo_de_excepcionalidade']
Contagem de valores unicos (inclui NaN) e apresentação da lista de valores: 
(até 1 valores únicos)

tipo_de_excepcionalidade :  1 valores únicos 
 ['----------'] 

Inclusão de campos

In [23]:
df_nauto.insert(0, 'ano_contratacao', pd.DatetimeIndex(df_nauto['data_da_contratacao']).year)
df_auto.insert(0, 'ano_contratacao', pd.DatetimeIndex(df_auto['data_da_contratacao']).year)

Consolidar operações em mesmo dataframe

In [24]:
compara_dois_dataframes(df_auto, df_nauto)
Colunas inexistentes no df_auto
['cnpj',
 'descricao_do_projeto',
 'numero_do_contrato',
 'valor_contratado_reais',
 'cnpj_da_instituicao_financeira_credenciada',
 'tipo_de_garantia',
 'situacao_do_contrato']
Colunas inexistentes no df_nauto
['cpf_cnpj',
 'valor_da_operacao_em_reais',
 'cnpj_do_agente_financeiro',
 'situacao_da_operacao']

A partir dos dados acima, faz-se necessário uniformizar nomes de colunas, para que os dataframes de operações automáticas e não automáticas possam ser consolidados em um único dataframe.

In [25]:
df_auto = df_auto.rename(columns={'valor_da_operacao_em_reais':'valor_contratado_reais',
                         'situacao_da_operacao':'situacao_do_contrato' })

df_nauto = df_nauto.rename(columns={'cnpj':'cpf_cnpj',
                         'cnpj_da_instituicao_financeira_credenciada':'cnpj_do_agente_financeiro'})

compara_dois_dataframes(df_auto, df_nauto)
Colunas inexistentes no df_auto
['descricao_do_projeto', 'numero_do_contrato', 'tipo_de_garantia']
Colunas inexistentes no df_nauto
[]

Compara-se as listas de colunas dos 2 dataframes, para a inclusão correta das colunas ausentes.

In [26]:
print('Colunas do dataframe df_auto:\n', df_auto.columns.values.tolist())
print('\nColunas do dataframe df_nauto:\n', df_nauto.columns.values.tolist())
Colunas do dataframe df_auto:
 ['ano_contratacao', 'cliente', 'cpf_cnpj', 'uf', 'municipio', 'municipio_codigo', 'data_da_contratacao', 'valor_contratado_reais', 'valor_desembolsado_reais', 'fonte_de_recurso_desembolsos', 'custo_financeiro', 'juros', 'prazo_carencia_meses', 'prazo_amortizacao_meses', 'modalidade_de_apoio', 'forma_de_apoio', 'produto', 'instrumento_financeiro', 'inovacao', 'area_operacional', 'setor_cnae', 'subsetor_cnae_agrupado', 'subsetor_cnae_codigo', 'subsetor_cnae_nome', 'setor_bndes', 'subsetor_bndes', 'porte_do_cliente', 'natureza_do_cliente', 'instituicao_financeira_credenciada', 'cnpj_do_agente_financeiro', 'situacao_do_contrato']

Colunas do dataframe df_nauto:
 ['ano_contratacao', 'cliente', 'cpf_cnpj', 'descricao_do_projeto', 'uf', 'municipio', 'municipio_codigo', 'numero_do_contrato', 'data_da_contratacao', 'valor_contratado_reais', 'valor_desembolsado_reais', 'fonte_de_recurso_desembolsos', 'custo_financeiro', 'juros', 'prazo_carencia_meses', 'prazo_amortizacao_meses', 'modalidade_de_apoio', 'forma_de_apoio', 'produto', 'instrumento_financeiro', 'inovacao', 'area_operacional', 'setor_cnae', 'subsetor_cnae_agrupado', 'subsetor_cnae_codigo', 'subsetor_cnae_nome', 'setor_bndes', 'subsetor_bndes', 'porte_do_cliente', 'natureza_do_cliente', 'instituicao_financeira_credenciada', 'cnpj_do_agente_financeiro', 'tipo_de_garantia', 'situacao_do_contrato']
In [27]:
df_auto.insert(3, 'descricao_do_projeto', 'Não se aplica')
df_auto.insert(7, 'numero_do_contrato', 'Não se aplica')
df_auto.insert(32, 'tipo_de_garantia', 'Não se aplica')

# Add Coluna para Tipo da Operação: Automatica e não Automatica
df_auto.insert(0, 'tipo_oper', 'Automatica')
df_nauto.insert(0, 'tipo_oper', 'Nao_Automatica')


print('Colunas do dataframe df_auto:\n', df_auto.columns.values.tolist())
print('\nColunas do dataframe df_nauto:\n', df_nauto.columns.values.tolist())
Colunas do dataframe df_auto:
 ['tipo_oper', 'ano_contratacao', 'cliente', 'cpf_cnpj', 'descricao_do_projeto', 'uf', 'municipio', 'municipio_codigo', 'numero_do_contrato', 'data_da_contratacao', 'valor_contratado_reais', 'valor_desembolsado_reais', 'fonte_de_recurso_desembolsos', 'custo_financeiro', 'juros', 'prazo_carencia_meses', 'prazo_amortizacao_meses', 'modalidade_de_apoio', 'forma_de_apoio', 'produto', 'instrumento_financeiro', 'inovacao', 'area_operacional', 'setor_cnae', 'subsetor_cnae_agrupado', 'subsetor_cnae_codigo', 'subsetor_cnae_nome', 'setor_bndes', 'subsetor_bndes', 'porte_do_cliente', 'natureza_do_cliente', 'instituicao_financeira_credenciada', 'cnpj_do_agente_financeiro', 'tipo_de_garantia', 'situacao_do_contrato']

Colunas do dataframe df_nauto:
 ['tipo_oper', 'ano_contratacao', 'cliente', 'cpf_cnpj', 'descricao_do_projeto', 'uf', 'municipio', 'municipio_codigo', 'numero_do_contrato', 'data_da_contratacao', 'valor_contratado_reais', 'valor_desembolsado_reais', 'fonte_de_recurso_desembolsos', 'custo_financeiro', 'juros', 'prazo_carencia_meses', 'prazo_amortizacao_meses', 'modalidade_de_apoio', 'forma_de_apoio', 'produto', 'instrumento_financeiro', 'inovacao', 'area_operacional', 'setor_cnae', 'subsetor_cnae_agrupado', 'subsetor_cnae_codigo', 'subsetor_cnae_nome', 'setor_bndes', 'subsetor_bndes', 'porte_do_cliente', 'natureza_do_cliente', 'instituicao_financeira_credenciada', 'cnpj_do_agente_financeiro', 'tipo_de_garantia', 'situacao_do_contrato']
In [28]:
# Criação de dataframe consolidado
df_consol = pd.concat([df_auto,df_nauto])
df_consol = df_consol.reset_index(drop=True)
df_consol.shape
Out[28]:
(2102928, 35)

Inclusão de campos em df consolidado

In [29]:
conditions = [
    (df_consol['tipo_oper']=='Nao_Automatica') & (df_consol['forma_de_apoio']=='DIRETA'),
    (df_consol['tipo_oper']=='Nao_Automatica') & (df_consol['forma_de_apoio']=='INDIRETA'),
    (df_consol['tipo_oper']=='Automatica') & (df_consol['forma_de_apoio']=='INDIRETA')]

oper_apoio = ['DIRETA Não Automatica','INDIRETA Não Automatica','INDIRETA Automatica']
df_consol['Oper_Apoio'] = np.select(conditions, oper_apoio)
print('Total de registros das Operações:')
display(df_consol['Oper_Apoio'].value_counts())
Total de registros das Operações:
INDIRETA Automatica        2083363
DIRETA Não Automatica        15457
INDIRETA Não Automatica       4108
Name: Oper_Apoio, dtype: int64

Inserir coluna com log dos valores, para facilitar a construção de histogramas e gráficos boxplots.

In [30]:
df_consol.insert(11, 'valor_contratado_log', np.log10(df_consol['valor_contratado_reais']+0.01))
df_consol.insert(13, 'valor_desembolsado_log', np.log10(df_consol['valor_desembolsado_reais']+0.01))
#df_consol.iloc[:, 10:13].head(10)
In [31]:
df_consol.columns
Out[31]:
Index(['tipo_oper', 'ano_contratacao', 'cliente', 'cpf_cnpj',
       'descricao_do_projeto', 'uf', 'municipio', 'municipio_codigo',
       'numero_do_contrato', 'data_da_contratacao', 'valor_contratado_reais',
       'valor_contratado_log', 'valor_desembolsado_reais',
       'valor_desembolsado_log', 'fonte_de_recurso_desembolsos',
       'custo_financeiro', 'juros', 'prazo_carencia_meses',
       'prazo_amortizacao_meses', 'modalidade_de_apoio', 'forma_de_apoio',
       'produto', 'instrumento_financeiro', 'inovacao', 'area_operacional',
       'setor_cnae', 'subsetor_cnae_agrupado', 'subsetor_cnae_codigo',
       'subsetor_cnae_nome', 'setor_bndes', 'subsetor_bndes',
       'porte_do_cliente', 'natureza_do_cliente',
       'instituicao_financeira_credenciada', 'cnpj_do_agente_financeiro',
       'tipo_de_garantia', 'situacao_do_contrato', 'Oper_Apoio'],
      dtype='object')

Verificação dos dados do dataframe

Para um determinado dataframe, são verificados: (checar_df)

  • total de registros;
  • quantidade e tipos de colunas;
  • quantidade de valores únicos;
  • quantidade de valores nulos (para identificar a necessidade de pre processamento dos dados).

Para uma determinada lista de valores, são verificadas: (checar_val_colunas_df_nunique)

  • valores únicos das colunas de interesse (para identificar as categorias).

Operações Automáticas

In [32]:
checar_df(df_auto)
Informações do dataframe: 
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 2083363 entries, 0 to 2083362
Data columns (total 35 columns):
 #   Column                              Dtype         
---  ------                              -----         
 0   tipo_oper                           object        
 1   ano_contratacao                     int64         
 2   cliente                             object        
 3   cpf_cnpj                            object        
 4   descricao_do_projeto                object        
 5   uf                                  object        
 6   municipio                           object        
 7   municipio_codigo                    object        
 8   numero_do_contrato                  object        
 9   data_da_contratacao                 datetime64[ns]
 10  valor_contratado_reais              int64         
 11  valor_desembolsado_reais            float64       
 12  fonte_de_recurso_desembolsos        object        
 13  custo_financeiro                    object        
 14  juros                               float64       
 15  prazo_carencia_meses                int64         
 16  prazo_amortizacao_meses             int64         
 17  modalidade_de_apoio                 object        
 18  forma_de_apoio                      object        
 19  produto                             object        
 20  instrumento_financeiro              object        
 21  inovacao                            object        
 22  area_operacional                    object        
 23  setor_cnae                          object        
 24  subsetor_cnae_agrupado              object        
 25  subsetor_cnae_codigo                object        
 26  subsetor_cnae_nome                  object        
 27  setor_bndes                         object        
 28  subsetor_bndes                      object        
 29  porte_do_cliente                    object        
 30  natureza_do_cliente                 object        
 31  instituicao_financeira_credenciada  object        
 32  cnpj_do_agente_financeiro           object        
 33  tipo_de_garantia                    object        
 34  situacao_do_contrato                object        
dtypes: datetime64[ns](1), float64(2), int64(4), object(28)
memory usage: 556.3+ MB

Número de observacoes na base de dados:  2083363
Total de  35 Colunas:  ['tipo_oper', 'ano_contratacao', 'cliente', 'cpf_cnpj', 'descricao_do_projeto', 'uf', 'municipio', 'municipio_codigo', 'numero_do_contrato', 'data_da_contratacao', 'valor_contratado_reais', 'valor_desembolsado_reais', 'fonte_de_recurso_desembolsos', 'custo_financeiro', 'juros', 'prazo_carencia_meses', 'prazo_amortizacao_meses', 'modalidade_de_apoio', 'forma_de_apoio', 'produto', 'instrumento_financeiro', 'inovacao', 'area_operacional', 'setor_cnae', 'subsetor_cnae_agrupado', 'subsetor_cnae_codigo', 'subsetor_cnae_nome', 'setor_bndes', 'subsetor_bndes', 'porte_do_cliente', 'natureza_do_cliente', 'instituicao_financeira_credenciada', 'cnpj_do_agente_financeiro', 'tipo_de_garantia', 'situacao_do_contrato']

Número de valores unicos (Não inclui NaN): 
Contagem Unicos
ano_contratacao 20
area_operacional 3
cliente 397313
cnpj_do_agente_financeiro 127
cpf_cnpj 98152
custo_financeiro 11
data_da_contratacao 5528
descricao_do_projeto 1
fonte_de_recurso_desembolsos 9
forma_de_apoio 1
inovacao 2
instituicao_financeira_credenciada 127
instrumento_financeiro 80
juros 1973
modalidade_de_apoio 1
municipio 5140
municipio_codigo 5418
natureza_do_cliente 5
numero_do_contrato 1
porte_do_cliente 4
prazo_amortizacao_meses 162
prazo_carencia_meses 57
produto 4
setor_bndes 4
setor_cnae 4
situacao_do_contrato 2
subsetor_bndes 20
subsetor_cnae_agrupado 44
subsetor_cnae_codigo 1640
subsetor_cnae_nome 1604
tipo_de_garantia 1
tipo_oper 1
uf 27
valor_contratado_reais 226554
valor_desembolsado_reais 229424
Número de valores nulos:
Contagem Nulos
ano_contratacao 0
area_operacional 0
cliente 0
cnpj_do_agente_financeiro 0
cpf_cnpj 0
custo_financeiro 0
data_da_contratacao 0
descricao_do_projeto 0
fonte_de_recurso_desembolsos 0
forma_de_apoio 0
inovacao 0
instituicao_financeira_credenciada 0
instrumento_financeiro 0
juros 436
modalidade_de_apoio 0
municipio 0
municipio_codigo 0
natureza_do_cliente 0
numero_do_contrato 0
porte_do_cliente 0
prazo_amortizacao_meses 0
prazo_carencia_meses 0
produto 0
setor_bndes 0
setor_cnae 0
situacao_do_contrato 0
subsetor_bndes 0
subsetor_cnae_agrupado 0
subsetor_cnae_codigo 0
subsetor_cnae_nome 0
tipo_de_garantia 0
tipo_oper 0
uf 0
valor_contratado_reais 0
valor_desembolsado_reais 2937
In [33]:
lista_col_interesse = ['uf']
checar_val_colunas_df_lista(df_auto, lista_col_interesse)
Contagem de valores unicos (inclui NaN) e apresentação da lista de valores:  

uf :  27 valores únicos 
 ['AC', 'AL', 'AM', 'AP', 'BA', 'CE', 'DF', 'ES', 'GO', 'MA', 'MG', 'MS', 'MT', 'PA', 'PB', 'PE', 'PI', 'PR', 'RJ', 'RN', 'RO', 'RR', 'RS', 'SC', 'SE', 'SP', 'TO'] 

In [34]:
checar_val_colunas_df_nunique(df_auto, 20)
Contagem de valores unicos (inclui NaN) e apresentação da lista de valores: 
(até 20 valores únicos)

tipo_oper :  1 valores únicos 
 ['Automatica'] 

forma_de_apoio :  1 valores únicos 
 ['INDIRETA'] 

tipo_de_garantia :  1 valores únicos 
 ['Não se aplica'] 

numero_do_contrato :  1 valores únicos 
 ['Não se aplica'] 

modalidade_de_apoio :  1 valores únicos 
 ['REEMBOLSÁVEL'] 

descricao_do_projeto :  1 valores únicos 
 ['Não se aplica'] 

situacao_do_contrato :  2 valores únicos 
 ['ATIVA', 'LIQUIDADA'] 

inovacao :  2 valores únicos 
 ['NÃO', 'SIM'] 

area_operacional :  3 valores únicos 
 ['AREA DE INDUSTRIA E SERVICOS', 'AREA DE MERC CAP, PARTIC E REEST DE EMPRESAS', 'AREA DE OPERACOES E CANAIS DIGITAIS'] 

porte_do_cliente :  4 valores únicos 
 ['GRANDE', 'MICRO', 'MÉDIA', 'PEQUENA'] 

setor_bndes :  4 valores únicos 
 ['AGROPECUÁRIA', 'COMERCIO/SERVICOS', 'INDUSTRIA', 'INFRA-ESTRUTURA'] 

setor_cnae :  4 valores únicos 
 ['AGROPECUÁRIA E PESCA', 'COMERCIO E SERVICOS', 'INDUSTRIA DE TRANSFORMAÇÃO', 'INDUSTRIA EXTRATIVA'] 

produto :  4 valores únicos 
 ['BNDES AUTOMÁTICO', 'BNDES FINAME', 'BNDES FINAME AGRÍCOLA', 'BNDES FINAME LEASING'] 

natureza_do_cliente :  5 valores únicos 
 ['ADMINISTRAÇÃO PÚBLICA DIRETA - GOVERNO ESTADUAL', 'ADMINISTRAÇÃO PÚBLICA DIRETA - GOVERNO FEDERAL', 'ADMINISTRAÇÃO PÚBLICA DIRETA - GOVERNO MUNICIPAL', 'PRIVADA', 'PÚBLICA INDIRETA'] 

fonte_de_recurso_desembolsos :  9 valores únicos 
 ['-', 'RECURSOS LIVRES - FAT', 'RECURSOS LIVRES - FND', 'RECURSOS LIVRES - ORGANISMOS', 'RECURSOS LIVRES - PRÓPRIOS', 'RECURSOS LIVRES - TESOURO', 'RECURSOS VINCULADOS - FAT DEPÓSITOS ESPECIAIS', 'RECURSOS VINCULADOS - FUNDO CLIMA', 'RECURSOS VINCULADOS - PIS/PASEP'] 

custo_financeiro :  11 valores únicos 
 ['75% da SELIC', '90% da SELIC', 'FAN', 'OUTROS', 'SELIC', 'TAXA FIXA', 'TJ453', 'TJ462', 'TJLP', 'TLP', 'US$ / CESTA'] 

subsetor_bndes :  20 valores únicos 
 ['AGROPECUÁRIA', 'ALIMENTO E BEBIDA', 'ATV. AUX. TRANSPORTES', 'CELULOSE E PAPEL', 'COMÉRCIO E SERVIÇOS', 'CONSTRUÇÃO', 'ENERGIA ELÉTRICA', 'EXTRATIVA', 'MATERIAL DE TRANSPORTE', 'MECÂNICA', 'METALURGIA E PRODUTOS', 'OUTRAS', 'OUTROS', 'OUTROS TRANSPORTES', 'QUÍMICA E PETROQUÍMICA', 'SERV. UTILIDADE PÚBLICA', 'TELECOMUNICAÇÕES', 'TRANSPORTE FERROVIÁRIO', 'TRANSPORTE RODOVIÁRIO', 'TÊXTIL E VESTUÁRIO'] 

ano_contratacao :  20 valores únicos 
 [2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021] 

Operações Não Automáticas

In [35]:
checar_df(df_nauto)
Informações do dataframe: 
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 19565 entries, 0 to 19564
Data columns (total 35 columns):
 #   Column                              Non-Null Count  Dtype         
---  ------                              --------------  -----         
 0   tipo_oper                           19565 non-null  object        
 1   ano_contratacao                     19565 non-null  int64         
 2   cliente                             19565 non-null  object        
 3   cpf_cnpj                            19565 non-null  object        
 4   descricao_do_projeto                19565 non-null  object        
 5   uf                                  19565 non-null  object        
 6   municipio                           19565 non-null  object        
 7   municipio_codigo                    19565 non-null  object        
 8   numero_do_contrato                  19565 non-null  object        
 9   data_da_contratacao                 19565 non-null  datetime64[ns]
 10  valor_contratado_reais              19565 non-null  float64       
 11  valor_desembolsado_reais            19565 non-null  float64       
 12  fonte_de_recurso_desembolsos        19565 non-null  object        
 13  custo_financeiro                    19565 non-null  object        
 14  juros                               19565 non-null  float64       
 15  prazo_carencia_meses                19565 non-null  int64         
 16  prazo_amortizacao_meses             19565 non-null  int64         
 17  modalidade_de_apoio                 19565 non-null  object        
 18  forma_de_apoio                      19565 non-null  object        
 19  produto                             19565 non-null  object        
 20  instrumento_financeiro              19565 non-null  object        
 21  inovacao                            19565 non-null  object        
 22  area_operacional                    19565 non-null  object        
 23  setor_cnae                          19565 non-null  object        
 24  subsetor_cnae_agrupado              19565 non-null  object        
 25  subsetor_cnae_codigo                19565 non-null  object        
 26  subsetor_cnae_nome                  19565 non-null  object        
 27  setor_bndes                         19565 non-null  object        
 28  subsetor_bndes                      19565 non-null  object        
 29  porte_do_cliente                    19565 non-null  object        
 30  natureza_do_cliente                 19565 non-null  object        
 31  instituicao_financeira_credenciada  19565 non-null  object        
 32  cnpj_do_agente_financeiro           19565 non-null  object        
 33  tipo_de_garantia                    19565 non-null  object        
 34  situacao_do_contrato                19565 non-null  object        
dtypes: datetime64[ns](1), float64(3), int64(3), object(28)
memory usage: 5.2+ MB

Número de observacoes na base de dados:  19565
Total de  35 Colunas:  ['tipo_oper', 'ano_contratacao', 'cliente', 'cpf_cnpj', 'descricao_do_projeto', 'uf', 'municipio', 'municipio_codigo', 'numero_do_contrato', 'data_da_contratacao', 'valor_contratado_reais', 'valor_desembolsado_reais', 'fonte_de_recurso_desembolsos', 'custo_financeiro', 'juros', 'prazo_carencia_meses', 'prazo_amortizacao_meses', 'modalidade_de_apoio', 'forma_de_apoio', 'produto', 'instrumento_financeiro', 'inovacao', 'area_operacional', 'setor_cnae', 'subsetor_cnae_agrupado', 'subsetor_cnae_codigo', 'subsetor_cnae_nome', 'setor_bndes', 'subsetor_bndes', 'porte_do_cliente', 'natureza_do_cliente', 'instituicao_financeira_credenciada', 'cnpj_do_agente_financeiro', 'tipo_de_garantia', 'situacao_do_contrato']

Número de valores unicos (Não inclui NaN): 
Contagem Unicos
ano_contratacao 20
area_operacional 9
cliente 3795
cnpj_do_agente_financeiro 47
cpf_cnpj 3788
custo_financeiro 29
data_da_contratacao 2974
descricao_do_projeto 5521
fonte_de_recurso_desembolsos 89
forma_de_apoio 2
inovacao 2
instituicao_financeira_credenciada 47
instrumento_financeiro 175
juros 557
modalidade_de_apoio 2
municipio 1057
municipio_codigo 1063
natureza_do_cliente 5
numero_do_contrato 7065
porte_do_cliente 4
prazo_amortizacao_meses 259
prazo_carencia_meses 101
produto 15
setor_bndes 4
setor_cnae 4
situacao_do_contrato 3
subsetor_bndes 19
subsetor_cnae_agrupado 44
subsetor_cnae_codigo 626
subsetor_cnae_nome 614
tipo_de_garantia 14
tipo_oper 1
uf 28
valor_contratado_reais 15023
valor_desembolsado_reais 16238
Número de valores nulos:
Contagem Nulos
ano_contratacao 0
area_operacional 0
cliente 0
cnpj_do_agente_financeiro 0
cpf_cnpj 0
custo_financeiro 0
data_da_contratacao 0
descricao_do_projeto 0
fonte_de_recurso_desembolsos 0
forma_de_apoio 0
inovacao 0
instituicao_financeira_credenciada 0
instrumento_financeiro 0
juros 0
modalidade_de_apoio 0
municipio 0
municipio_codigo 0
natureza_do_cliente 0
numero_do_contrato 0
porte_do_cliente 0
prazo_amortizacao_meses 0
prazo_carencia_meses 0
produto 0
setor_bndes 0
setor_cnae 0
situacao_do_contrato 0
subsetor_bndes 0
subsetor_cnae_agrupado 0
subsetor_cnae_codigo 0
subsetor_cnae_nome 0
tipo_de_garantia 0
tipo_oper 0
uf 0
valor_contratado_reais 0
valor_desembolsado_reais 0
In [36]:
lista_col_interesse = ['uf']
checar_val_colunas_df_lista(df_nauto, lista_col_interesse)
# Observação: o que seria UF = IE?
Contagem de valores unicos (inclui NaN) e apresentação da lista de valores:  

uf :  28 valores únicos 
 ['AC', 'AL', 'AM', 'AP', 'BA', 'CE', 'DF', 'ES', 'GO', 'IE', 'MA', 'MG', 'MS', 'MT', 'PA', 'PB', 'PE', 'PI', 'PR', 'RJ', 'RN', 'RO', 'RR', 'RS', 'SC', 'SE', 'SP', 'TO'] 

In [37]:
checar_val_colunas_df_nunique(df_nauto, 20)
Contagem de valores unicos (inclui NaN) e apresentação da lista de valores: 
(até 20 valores únicos)

tipo_oper :  1 valores únicos 
 ['Nao_Automatica'] 

inovacao :  2 valores únicos 
 ['NÃO', 'SIM'] 

forma_de_apoio :  2 valores únicos 
 ['DIRETA', 'INDIRETA'] 

modalidade_de_apoio :  2 valores únicos 
 ['NÃO REEMBOLSÁVEL', 'REEMBOLSÁVEL'] 

situacao_do_contrato :  3 valores únicos 
 ['-', 'ATIVO', 'LIQUIDADO'] 

porte_do_cliente :  4 valores únicos 
 ['GRANDE', 'MICRO', 'MÉDIA', 'PEQUENA'] 

setor_bndes :  4 valores únicos 
 ['AGROPECUÁRIA', 'COMERCIO/SERVICOS', 'INDUSTRIA', 'INFRAESTRUTURA'] 

setor_cnae :  4 valores únicos 
 ['AGROPECUÁRIA E PESCA', 'COMERCIO E SERVICOS', 'INDUSTRIA DE TRANSFORMAÇÃO', 'INDUSTRIA EXTRATIVA'] 

natureza_do_cliente :  5 valores únicos 
 ['ADMINISTRAÇÃO PÚBLICA DIRETA - GOVERNO ESTADUAL', 'ADMINISTRAÇÃO PÚBLICA DIRETA - GOVERNO FEDERAL', 'ADMINISTRAÇÃO PÚBLICA DIRETA - GOVERNO MUNICIPAL', 'PRIVADA', 'PÚBLICA INDIRETA'] 

area_operacional :  9 valores únicos 
 ['AREA DE ENERGIA', 'AREA DE ESTRUTURACAO DE EMPRESAS E DESINVESTIMENTOS', 'AREA DE ESTRUTURACAO DE PARCERIAS DE INVESTIMENTOS', 'AREA DE GESTAO PUBLICA E SOCIOAMBIENTAL', 'AREA DE INDUSTRIA E SERVICOS', 'AREA DE MERC CAP, PARTIC E REEST DE EMPRESAS', 'AREA DE OPERACOES E CANAIS DIGITAIS', 'AREA DE PLANEJAMENTO ESTRATEGICO', 'AREA DE SANEAMENTO E TRANSPORTE'] 

tipo_de_garantia :  14 valores únicos 
 ['COM DISPENSA DE GARANTIA', "COMPROMISSO DE DESEMPENHO FINANCEIRO ('COVENANTS')", "COMPROMISSO DE DESEMPENHO FINANCEIRO ('COVENANTS') / OUTRA, DE NATUREZA ESPECÍFICA OU MISTA", 'DEBÊNTURE QUIROGRAFÁRIA', 'DEFINIDA PELO AGENTE FINANCEIRO', 'NÃO SE APLICA', 'OUTRA, DE NATUREZA ESPECÍFICA OU MISTA', 'PESSOAL', 'PESSOAL / OUTRA, DE NATUREZA ESPECÍFICA OU MISTA', 'REAL', 'REAL / OUTRA, DE NATUREZA ESPECÍFICA OU MISTA', 'REAL / PESSOAL', 'REAL / PESSOAL / OUTRA, DE NATUREZA ESPECÍFICA OU MISTA', 'SEM REGISTRO DE GARANTIA'] 

produto :  15 valores únicos 
 ['BNDES CRÉDITO DIRETO MÉDIAS EMPRESAS', 'BNDES DEBENTURES SIMPLES', 'BNDES DEBENTURES SUSTENTAVEIS E DE INFRAESTRUTURA', 'BNDES DIRETO 10', 'BNDES EMPRÉSTIMO PONTE', 'BNDES EXIM PÓS-EMBARQUE', 'BNDES FINAME', 'BNDES FINEM', 'BNDES LIMITE DE CRÉDITO', 'BNDES MICROCRÉDITO', 'BNDES NÃO REEMBOLSÁVEL', 'BNDES PROJECT FINANCE', 'BNDES RENEGOCIAÇÃO', 'OPERAÇÃO FINANCEIRA', 'OUTROS'] 

subsetor_bndes :  19 valores únicos 
 ['AGROPECUÁRIA', 'ALIMENTO E BEBIDA', 'ATV. AUX. TRANSPORTES', 'CELULOSE E PAPEL', 'COMÉRCIO E SERVIÇOS', 'CONSTRUÇÃO', 'ENERGIA ELÉTRICA', 'EXTRATIVA', 'MATERIAL DE TRANSPORTE', 'MECÂNICA', 'METALURGIA E PRODUTOS', 'OUTRAS', 'OUTROS TRANSPORTES', 'QUÍMICA E PETROQUÍMICA', 'SERV. UTILIDADE PÚBLICA', 'TELECOMUNICAÇÕES', 'TRANSPORTE FERROVIÁRIO', 'TRANSPORTE RODOVIÁRIO', 'TÊXTIL E VESTUÁRIO'] 

ano_contratacao :  20 valores únicos 
 [2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021] 

Estatísticas das Operações

Estabelecendo algumas variáveis

In [38]:
ano_min = np.min(df_consol['ano_contratacao'])
ano_max = np.max(df_consol['ano_contratacao'])
lista_anos = np.arange(ano_min, ano_max,1)
vlr_contr_soma_ano_bi = (df_consol.groupby(['ano_contratacao'])\
                         ['valor_contratado_reais'].sum()/1000000000).reset_index() # em bilhoes

Estatísticas descritivas do Valor Contratado

Verificação do comportamento estatístico dos valores contratados (considerando-se todos os valores em todos os anos).

In [39]:
print(color.BOLD + color.BLUE + 'Estatisticas - Operações Automaticas' + color.END)
print(color.BOLD + color.BLUE + 50*'*' + color.END)
display(df_auto['valor_contratado_reais'].describe())

print(color.BOLD + color.BLUE + 'Estatisticas - Operações Não Automaticas')
print(color.BOLD + color.BLUE + 50*'*' + color.END)
display(df_nauto['valor_contratado_reais'].describe())

print(color.BOLD + color.BLUE + 'Estatisticas - Dataframe consolidado')
print(color.BOLD + color.BLUE + 50*'*' + color.END)
display(df_consol['valor_contratado_reais'].describe())
Estatisticas - Operações Automaticas
**************************************************
count      2083363.00
mean        273316.68
std        1671683.30
min              8.00
25%          41785.00
50%         112500.00
75%         233000.00
max     1000000000.00
Name: valor_contratado_reais, dtype: float64
Estatisticas - Operações Não Automaticas
**************************************************
count        19565.00
mean      46964792.21
std      203148551.97
min            229.12
25%        2385165.75
50%        9385000.00
75%       30665000.00
max     9889997969.99
Name: valor_contratado_reais, dtype: float64
Estatisticas - Dataframe consolidado
**************************************************
count      2102928.00
mean        707719.91
std       20169298.42
min              8.00
25%          42316.00
50%         114520.00
75%         239490.25
max     9889997969.99
Name: valor_contratado_reais, dtype: float64

**Avaliação**:

  • Médias elevadas e medianas baixas indicam presença de poucos valores contratados muito altos que distorcem a média.
  • desvio padrão elevado indica que há muitos dados (valores contratados) espalhados e afastados da média
  • Desta forma, Valores contratados possui grande variabilidade.

Resumo das Operações em números...

  • Operações Automáticas, em maior quantidade (~ 2 milhões de operações), respondem pelos menores valores contratados (média de 200 mil).
  • Operações Não automáticas, embora em menor quantidade (~20 mil operações), respondem pelos maiores valores contratados (média de 40 milhões).

Total do Valor Contratado - por Ano (acumulado)

Agrupamento/ Soma de todos os valores contratados no ano.

In [40]:
print('Total dos Valores Contratados (em bilhões) nos anos de %s a %s: ' % (ano_min, ano_max), 
      np.round(df_consol['valor_contratado_reais'].sum()/1000000000))

display(vlr_contr_soma_ano_bi)
Total dos Valores Contratados (em bilhões) nos anos de 2002 a 2021:  1488.0
ano_contratacao valor_contratado_reais
0 2002 22.41
1 2003 18.70
2 2004 24.16
3 2005 30.61
4 2006 42.83
5 2007 72.05
6 2008 70.71
7 2009 137.43
8 2010 114.36
9 2011 118.97
10 2012 194.61
11 2013 167.05
12 2014 137.42
13 2015 64.31
14 2016 41.69
15 2017 54.08
16 2018 68.99
17 2019 40.95
18 2020 54.91
19 2021 12.03
In [41]:
f, axes = plt.subplots(1, 1,  figsize=(18, 10))
g = sns.lineplot(x='ano_contratacao', y='valor_contratado_reais', 
                 data=vlr_contr_soma_ano_bi, color ='g', linewidth=2.5, label='Valor Contratado')
g.axhline(110, linestyle='--', linewidth = 1.5, color='red', label='Pico da Soma dos valores contratados')

axes.set_title('Total/Soma do Valor Contratado - por Ano', fontsize=20)
axes.set_ylabel('Valor Contratado (bilhões)', fontsize=14)
axes.set(xlabel='') 

xlocs, xlabels = plt.xticks()
ylocs, ylabels = plt.yticks()
plt.setp(xlabels, fontsize=14, rotation=90)
plt.setp(ylabels, fontsize=14)
plt.xticks(np.arange(ano_min, ano_max+1, 1))
plt.legend(fontsize=14)

plt.show()

O objetivo deste gráfico é exibir a soma de todos os valores contratados, por ano, ao longo dos anos - a fim de notarmos a tendência ou não de crescimento.

  • Nota-se um crescimento de 2002-2012 (com leve queda em 2010-2011)
  • Em seguida, há uma queda dos montantes a partir de 2013.
  • Excepcionalmente, valores contratados aumentaram expressivamente no periodo de 2009-2014 (especialmente em 2009 e 2012).

Observação: Comparando-se este gráfico com o boxplot seguinte (BoxPlot da distribuição dos Valores Contratados), percebe-se claramente que o pico de investimentos nos anos de 2009 e 2012 foi devido a contratos pontuais. Em outras palavras: aparentemente, não houve um aumento expressivo na quantidade de contratos. O que aparentemente houve foi que apenas poucos contratos (2 a 3 contratos específicos) de valor muito elevado resultaram na ocorrência dos picos.

BoxPlot da distribuição dos Valores Contratados (brutos) por Ano

Verificação da dispersão dos valores contratados ao longo dos anos.

In [42]:
f, axes = plt.subplots(1, 1,  figsize=(16, 6))
g = sns.boxplot(x='ano_contratacao', y='valor_contratado_reais', data=df_consol)
g.axhline(5000000000, linestyle='--', linewidth = 1.0, color='red', label='Contratos pontuais bastante elevados')
g.axhline(3000000000, linestyle='--', linewidth = 1.0, color='orange', label='Contratos acima de 3 bilhões')

axes.set_title('Distribuição dos Valores Contratados - 2002 a 2021', fontsize=20)
axes.set_ylabel('Valor Contratado (bruto)', fontsize=14)
axes.set(xlabel='') 

ylocs, ylabels = plt.yticks()
plt.setp(xlabels, fontsize=14, rotation=90)
plt.setp(ylabels, fontsize=14)
plt.legend(fontsize=14)

plt.show()

**Avaliação**:

  • Há poucos valores contratados exorbitantes (acima de 3 bilhões).
  • A grande maioria dos valores contratados são baixos.
  • O ano em que claramente ocorreu o maior valor contratado (talvez um subcredito isolado) foi em 2009 (identificação de outliers).

A grande variabilidade dos valores contratados dificulta o entendimento a respeito da sua distribuição para valores mais baixos. Desta forma, será utilizada a notação logarítima nos próximos gráficos.

BoxPlot da distribuição dos Valores Contratados (log) por Ano

In [43]:
f, axes = plt.subplots(1, 1,  figsize=(16, 8))
g = sns.boxplot(x=df_consol['ano_contratacao'], 
            y=df_consol['valor_contratado_log'], ax=axes, color='lightblue')

g.axhline(9.5, linestyle='--', linewidth = 1.5, color='r', label='Maiores outliers')
g.axhline(3.5, linestyle='--', linewidth = 1.5, color='orange', label='Valores irrisórios (abaixo de $3000)')

major_ticks = np.arange(0, 12, 1)
minor_ticks = np.arange(0, 12, 0.5)
axes.set_yticks(major_ticks)
axes.set_yticks(minor_ticks, minor=True)
axes.grid(which='both', axis='y')
xlocs, xlabels = plt.xticks()
ylocs, ylabels = plt.yticks()
plt.setp(xlabels, fontsize=14, rotation=90)
plt.setp(ylabels, fontsize=14)
axes.set_title('Distribuição dos Valores Contratados (log) - 2002 a 2021', fontsize=16)
axes.set(xlabel=''); 
axes.set_ylabel('Valor Contratado (log)', fontsize=14) 

axes.legend(fontsize=13, loc='upper center')

plt.show()

**Avaliação**:

  • Usando-se notação logarítmica, torna-se mais fácil visualizar a variação dos valores contratados de menor montante.
  • Desta forma, pode-se afirmar que 50% dos valores de contratos oscilam entre $10.000 e 1.000.000

BoxPlot da distribuição dos Valores Contratados (log) por Ano/ Apoio

In [44]:
boxplot_vlr_contr_hue(df_consol, 'forma_de_apoio', 'viridis')

**Avaliação**:

  • Olhando-se de forma mais detalhada, percebe-se que a forma DIRETA responde, em 50%, por contratos de maior valor, em comparação com a forma indireta.
  • Os maiores outliers são também provenientes das operações da forma DIRETA.

BoxPlot da distribuição dos Valores Contratados (log) por Ano/ Operação

In [45]:
boxplot_vlr_contr_hue(df_consol, 'tipo_oper', 'plasma')

**Avaliação**:

  • Olhando-se de forma mais detalhada, percebe-se que a operação Não automática responde, em 50%, por contratos de maior valor, em comparação com a operação Automática.
  • Os maiores outliers são também provenientes das operações Não automáticas.

BoxPlot da distribuição dos Valores Contratados (log) por Ano/ Porte Cliente

In [46]:
boxplot_vlr_contr_hue(df_consol, 'porte_do_cliente', 'hot_r')

**Avaliação**:

  • Olhando-se de forma mais detalhada, percebe-se que contratos de maior valor são concedidos às grandes empresas. Uma exceção ocorreu em 2016, concedidos às médias empresas.
  • Os maiores outliers são também provenientes das operações com GRANDES empresas.

BoxPlot da distribuição dos Valores Contratados (log) por Ano/ Natureza do Cliente

In [47]:
boxplot_vlr_contr_hue(df_consol, 'natureza_do_cliente', 'Set1')

**Avaliação**:

  • Olhando-se de forma mais detalhada, percebe-se que contratos de maior valor são concedidos para AP Direta e Indireta.
  • Contratos menores são das empresas privadas (embora os maiores outliers também são de contratos com as empresas privadas).

BoxPlot da distribuição dos Valores Contratados (log) por Ano/ Setor Bndes e CNAE

In [48]:
boxplot_vlr_contr_hue(df_consol, 'setor_bndes', 'hsv')
boxplot_vlr_contr_hue(df_consol, 'setor_cnae', 'hsv')

**Avaliação - Setor BNDES**:

  • Olhando-se de forma mais detalhada, percebe-se claramente que contratos de maior valor são concedidos para o setor de INFRAESTRUTURA (o que de fato compreende aos objetivos de desenvolvimento do país).
  • Os maiores outliers, por outro lado, são provenientes não só da INFRAESTRUTURA, mas também de outros setores, como INDUSTRIA (2009, 2012) e COMERCIO/SERVIÇOS (2012, 2017).
  • Nota-se que houve maior crescimento de investimentos para a AGROPECUARIA a partir de 2011.

**Avaliação - Setor CNAE**:

  • Os resultados são diferentes quando se usa o setor CNAE, que não lista a INFRAESTRUTURA. Desta forma, os investimentos aparentam estarem mais constantes pelos setores presentes (nenhum se sobrepõe aos demais).
  • A mesma análise se aplica ao setor de AGROPECUÁRIA: maior crescimento de investimentos a partir de 2011

Estatísticas das Operações - por Localidades

Nota:

  • Para análises de operações por UF ou Municipios, foi necessário excluir operações (0,3%) sem a informação de municipio.

Dados do IBGE adicionados ao dataframe consolidado

In [49]:
df_consol_mun = pd.merge(df_consol, ibge[['COD_IBGE', 'REGIAO', 'SIGLA_UF', 'NOME_UF', 'NOME_MUNICIPIO','CAPITAL','POP2013',
                                          'LAT', 'LNG', 'ALT','POP2013', 'CAPITAL']], 
                          left_on='municipio_codigo', 
                          right_on='COD_IBGE',  
                          how='left', indicator=True)
In [50]:
Regioes = ibge['REGIAO'].sort_values().unique()
print('Regiões: ', Regioes)
print('\nTotal de registros do dataframe df_consol_mun:', df_consol_mun.shape[0])
print('Total de registros com os dados do IBGE atualizados:')
display(df_consol_mun['_merge'].value_counts())

print('Quantidade de registros de operações sem a informação de Municipio:')
display(df_consol_mun[df_consol_mun['_merge']=='left_only'][['municipio']].value_counts())

print('Apresenta as UFs que contém algum campo de Municipio sem informação:')
display((df_consol_mun[df_consol_mun['_merge']=='left_only'][['uf']].value_counts()).index.values)
Regiões:  ['CO' 'N' 'NE' 'S' 'SE']

Total de registros do dataframe df_consol_mun: 2102928
Total de registros com os dados do IBGE atualizados:
both          2096439
left_only        6489
right_only          0
Name: _merge, dtype: int64
Quantidade de registros de operações sem a informação de Municipio:
municipio    
SEM MUNICÍPIO    6273
DIVERSOS          190
SEM MUNICIPIO      26
dtype: int64
Apresenta as UFs que contém algum campo de Municipio sem informação:
array([('IE',), ('SP',), ('RS',), ('MG',), ('PR',), ('RJ',), ('BA',),
       ('SC',), ('RN',), ('PI',), ('MT',), ('CE',), ('GO',), ('PE',),
       ('MS',), ('PA',), ('MA',), ('SE',), ('PB',), ('ES',), ('DF',),
       ('AC',), ('TO',), ('AM',), ('RO',), ('AP',), ('AL',), ('RR',)],
      dtype=object)
In [51]:
# Retirar os registros sem informação de municipio
df_consol_mun = df_consol_mun[df_consol_mun['_merge'] == 'both']
df_consol_mun.shape
Out[51]:
(2096439, 51)

Total de Municipios investidos por Estado

Exibe o total de municipios por UF que ja receberam investimentos em algum ano, em comparação com o total de municipios existentes em cada UF.

In [52]:
#stats_tot_mun_uf(df_consol_mun[df_consol_mun['ano_contratacao']==2002])
stats_tot_mun_uf(df_consol_mun)
Total de Municipios IBGE:  5570 Municípios
Total de Municipios investidos:  5421 Municípios

**Avaliação**:

  • Pode-se perceber alguns municipios que nunca receberam investimentos (caso do PI e MA).
In [53]:
#Verificação de algum ano especifico
#stats_tot_mun_uf(df_consol_mun[df_consol_mun['ano_contratacao']==2003])

Agrupamento de Valores Contratados por Municipio/Ano

In [243]:
df_vlr_ano_mun = df_consol_mun.groupby(['ano_contratacao','REGIAO','uf','NOME_UF','municipio_codigo','NOME_MUNICIPIO',\
                                       'LAT','LNG','ALT'])['valor_contratado_reais'].agg(['sum','min','max','count'])\
                                        .reset_index()
df_vlr_ano_mun = df_vlr_ano_mun.rename(columns={'sum':'Soma_ValorContr',
                                                'min':'Menor_ValorContr', 
                                                'max':'Maior_ValorContr',
                                                'count':'Total_Contr'})
df_vlr_ano_mun.insert(10, 'Soma_ValorContr_log', np.log10(df_vlr_ano_mun['Soma_ValorContr']+0.01))

print(df_vlr_ano_mun.shape)
display(df_vlr_ano_mun.head())
(70803, 14)
ano_contratacao REGIAO uf NOME_UF municipio_codigo NOME_MUNICIPIO LAT LNG ALT Soma_ValorContr Soma_ValorContr_log Menor_ValorContr Maior_ValorContr Total_Contr
0 2002 CO DF Distrito Federal 5300108 Brasília -15.79 -47.89 1115.25 413182635.00 8.62 1248.00 76143600.00 259
1 2002 CO GO Goiás 5200134 Acreúna -17.40 -50.37 542.39 1481082.00 6.17 20022.00 150000.00 17
2 2002 CO GO Goiás 5200175 Água Fria de Goiás -14.99 -47.78 856.26 223328.00 5.35 21301.00 107527.00 3
3 2002 CO GO Goiás 5200258 Águas Lindas de Goiás -15.74 -48.28 1208.67 80000.00 4.90 80000.00 80000.00 1
4 2002 CO GO Goiás 5200308 Alexânia -16.09 -48.51 1076.72 347990.00 5.54 6500.00 203685.00 4

Visualização do total de municipios financiados - por Ano

Para cada UF, em cada ano, exibe total de municipios contemplados com investimentos

In [55]:
total_mun_UF = df_vlr_ano_mun.groupby(['ano_contratacao','REGIAO', 'uf'])['municipio_codigo'].nunique().reset_index()
total_mun_UF.columns = ['ANO','REGIAO', 'UF','QTD_MUNIC'] 
total_mun_UF = total_mun_UF.sort_values(by=['ANO','QTD_MUNIC'], ascending=[True, False])

ix = 1
fig = plt.figure(figsize = (20,10))
cores = sns.color_palette("tab20c")

for R in Regioes:
    if ix <= 1:
        ax2 = fig.add_subplot(1,1,1)
        
        my_order = total_mun_UF[total_mun_UF['REGIAO']==R].groupby(['UF'])['QTD_MUNIC']\
                            .count().sort_values(ascending=True).iloc[::-1].index
        
        sns.barplot(x='UF', y='QTD_MUNIC', hue='ANO', 
            data=total_mun_UF[total_mun_UF['REGIAO']==R], 
            ax=ax2, palette=cores, order=my_order)
        
        ax2.set_title('Total Municipios financiados na Regiao %s - 2002 a 2021' %R, fontsize=20)
        ax2.set_ylabel(''); ax2.set_xlabel('')
        
        xlocs, xlabels = plt.xticks()
        ylocs, ylabels = plt.yticks()
        plt.setp(xlabels, rotation=0, fontsize=16)
        plt.setp(ylabels, fontsize=16)
     
    ix = ix +1
    if ix == 2: 
        fig = plt.figure(figsize = (20,10))
        ix =1

plt.tight_layout()
<Figure size 1440x720 with 0 Axes>

**Avaliação**:
Os plots acima foram criados para facilitar a visualização de quais UFs, dado um determinado ano, estão com um maior número de municípios recebendo mais investimentos. Desta forma, pode-se verificar, por exemplo:

  • ocorre oscilação da distribuição dos investimentos nos municipios das UFs. É o caso de GO, PA e BA por exemplo. Em determinados anos, muitos municipios recebem investimentos; em outros anos, o número de municípios é bastante reduzido. No caso da BA, há anos em que mais de 300 municípios recebem investimentos; em outros anos, reduz-se este número para menos de 150 municipios.
  • Há UFs em que o número de municípios recebendo investimentos é mais constante: é o caso do RJ, ES, AP e MS.

Visualização do total de valores contratados - por UF/ Ano

Para cada UF, em cada ano, exibe o total de valores investidos.

In [56]:
total_vlr_cntr_UF = df_vlr_ano_mun.groupby(['ano_contratacao','REGIAO', 'uf'])['Soma_ValorContr'].sum().reset_index()
total_vlr_cntr_UF.columns = ['ANO','REGIAO', 'UF','Soma_ValorContr'] 
total_vlr_cntr_UF = total_vlr_cntr_UF.sort_values(by=['ANO','Soma_ValorContr'], ascending=[True, False])

ix = 1
fig = plt.figure(figsize = (20,10))
cores = sns.color_palette("tab20c")

for R in Regioes:
    if ix <= 1:
        ax2 = fig.add_subplot(1,1,1)
        
        my_order = total_vlr_cntr_UF[total_vlr_cntr_UF['REGIAO']==R].groupby(['UF'])['Soma_ValorContr']\
                            .count().sort_values(ascending=True).iloc[::-1].index
        
        sns.barplot(x='UF', y='Soma_ValorContr', hue='ANO', 
            data=total_vlr_cntr_UF[total_vlr_cntr_UF['REGIAO']==R], 
            ax=ax2, palette=cores, order=my_order)
        
        ax2.set_title('Total Valores Contratados na Regiao %s - 2002 a 2021' %R, fontsize=20)
        ax2.set_ylabel(''); ax2.set_xlabel('')
        
        xlocs, xlabels = plt.xticks()
        ylocs, ylabels = plt.yticks()
        plt.setp(xlabels, rotation=0, fontsize=16)
        plt.setp(ylabels, fontsize=16)
     
    ix = ix +1
    if ix == 2: 
        fig = plt.figure(figsize = (20,10))
        ix =1

plt.tight_layout()
<Figure size 1440x720 with 0 Axes>

**Avaliação**:

O plot acima procura mostrar o total investido em cada UF, para cada ano. Pode-se perceber:

  • UFs que receberam os maiores investimentos foram PE e RO (2009);
  • Não há uma certa constância: uma UF pode receber um montante considerável em um ano e ja receber muito menos no ano seguinte.

StripPlot da distribuição dos Valores Contratados (log) por UF

In [57]:
%%time
features_categoricas = ['uf']
ix = 1

fig = plt.figure(figsize = (55,20))

# c = para cada coluna
for c in list(df_consol[features_categoricas]):
    if ix <= 3:
        ax2 = fig.add_subplot(2,3,ix+2)
        my_order = df_consol.groupby(by=c)['valor_contratado_log'].median().sort_values(ascending=False).iloc[::-1].index
        sns.stripplot(x=df_consol[c], y=(df_consol['valor_contratado_log']), ax=ax2, order=my_order, linewidth=0.5)
        ax2.set(ylabel="valor_contratado_log")
            
    locs, labels = plt.xticks()
    plt.setp(labels, rotation=90, fontsize=12)
            
    ix = ix +1
    if ix == 2: 
        fig = plt.figure(figsize = (55,12))
        ix =1

plt.tight_layout()
Wall time: 1.85 s
<Figure size 3960x864 with 0 Axes>

**Avaliação**:

O plot acima procura mostrar a distribuição dos valores de contrato por UF, considerando-se todas as operações no período de 2002-2021. Desta forma, todas as UFs ja receberam montantes similares em algum momento - sendo que o maior valor ja contratado ocorreu no estado de PE.

Análise das Operações

Informações Resumidas

In [58]:
oper_info_resumidas(df_nauto)
Total de registros de Operações Contratadas na Forma Nao_Automatica: 19565 operações
   - Forma DIRETA:  15457
   - Forma INDIRETA:  4108

Total Valor Contratado (em R$ bilhões): 918.87
Total Valor Desembolsado (em R$ bilhões): 772.14
7065 Contratos no período:  2002-01-02 a 2021-05-31
Total de 1063 municipios contemplados em 28 estados.
In [59]:
oper_info_resumidas(df_auto)
Total de registros de Operações Contratadas na Forma Automatica: 2083363 operações
   - Forma DIRETA:  0
   - Forma INDIRETA:  2083363

Total Valor Contratado (em R$ bilhões): 569.42
Total Valor Desembolsado (em R$ bilhões): 557.79
1 Contratos no período:  2002-01-02 a 2021-05-31
Total de 5418 municipios contemplados em 27 estados.

Análise de Contratos

Estabelecendo algumas variáveis

In [60]:
ano_min = np.min(df_consol['ano_contratacao'])
ano_max = np.max(df_consol['ano_contratacao'])
vlr_contr_soma_bi = df_consol['valor_contratado_reais'].sum()/1000000000 # em bilhoes
vlr_contr_soma_ano_bi = df_consol.groupby(['ano_contratacao'])['valor_contratado_reais'].sum()/1000000000 # em bilhoes
nticks = 19

Tabela de Valores Contratados - acumulados

In [61]:
print('Tabela de Valores Contratados (em bilhões) nos anos de %s a %s:' %(ano_min, ano_max))
df_consol_totais = (df_consol.groupby(['forma_de_apoio','tipo_oper','modalidade_de_apoio'])\
                                     ['valor_contratado_reais'].sum()/1000000000).reset_index()
df_consol_totais['Perc(%)'] = df_consol_totais['valor_contratado_reais']/vlr_contr_soma_bi*100
df_consol_totais
Tabela de Valores Contratados (em bilhões) nos anos de 2002 a 2021:
Out[61]:
forma_de_apoio tipo_oper modalidade_de_apoio valor_contratado_reais Perc(%)
0 DIRETA Nao_Automatica NÃO REEMBOLSÁVEL 5.86 0.39
1 DIRETA Nao_Automatica REEMBOLSÁVEL 809.99 54.42
2 INDIRETA Automatica REEMBOLSÁVEL 569.42 38.26
3 INDIRETA Nao_Automatica REEMBOLSÁVEL 103.02 6.92

**Avaliação**:

  • Conforme a tabela acima, os valores provenientes da modalidade "NÃO REEMBOLSÁVEL" são irrisórios. Por este motivo, os gráficos seguintes irão desconsiderar esta variável.
  • O gráfico abaixo mostra o peso relativo destes valores não reembolsáveis (muito pequeno) com os demais valores reembolsáveis.
In [62]:
t_vlr_mod_apoio = df_consol.groupby(['ano_contratacao','modalidade_de_apoio'])['valor_contratado_reais'].sum()/1000000
t_vlr_mod_apoio = t_vlr_mod_apoio.reset_index() # em mil

fig = px.bar(t_vlr_mod_apoio.sort_values(by=['ano_contratacao','modalidade_de_apoio'], ascending=[True,False]),
             x='ano_contratacao', y='valor_contratado_reais', color='modalidade_de_apoio',
             color_discrete_sequence=px.colors.qualitative.Safe,
             barmode = 'stack', width=900, height=400)

fig.update_layout(title={'text': "Valores Contratados por Modalidade de apoio",
                         'y':0.95, 'x':0.5, 'xanchor': 'center', 'yanchor': 'top'},
                  yaxis=dict(title='Valor Contratado (milhões)', titlefont_size=14,tickfont_size=14),
                  xaxis=dict(title=''),
                  legend=dict(x=0.05,y=0.95))
fig.update_xaxes(nticks=nticks)
fig.show()
In [63]:
# Retirando a coluna de modalidade de apoio
print('Tabela de Valores Contratados (em bilhões) nos anos de %s a %s:' %(ano_min, ano_max))
df_consol_totais = (df_consol.groupby(['forma_de_apoio','tipo_oper'])\
                                     ['valor_contratado_reais'].sum()/1000000000).reset_index()
df_consol_totais['Perc(%)'] = df_consol_totais['valor_contratado_reais']/vlr_contr_soma_bi*100
df_consol_totais
Tabela de Valores Contratados (em bilhões) nos anos de 2002 a 2021:
Out[63]:
forma_de_apoio tipo_oper valor_contratado_reais Perc(%)
0 DIRETA Nao_Automatica 815.85 54.82
1 INDIRETA Automatica 569.42 38.26
2 INDIRETA Nao_Automatica 103.02 6.92

Tabela de Valores Contratados - por ano

In [64]:
print('Tabela de Valores Contratados (em bilhões) - por Ano')
df_consol_tot_ano = (df_consol.groupby(['ano_contratacao','forma_de_apoio','tipo_oper'])\
                                     ['valor_contratado_reais'].sum()/1000000000)
df_consol_tot_ano_perc = df_consol_tot_ano /(df_consol_tot_ano.groupby('ano_contratacao').sum())*100
df_consol_totais_ano = pd.DataFrame({'valor_contratado_reais':df_consol_tot_ano,
                                     'Perc(%)':df_consol_tot_ano_perc
                                    }).reset_index()
df_consol_totais_ano
Tabela de Valores Contratados (em bilhões) - por Ano
Out[64]:
ano_contratacao forma_de_apoio tipo_oper valor_contratado_reais Perc(%)
0 2002 DIRETA Nao_Automatica 13.73 61.26
1 2002 INDIRETA Automatica 6.80 30.35
2 2002 INDIRETA Nao_Automatica 1.88 8.40
3 2003 DIRETA Nao_Automatica 8.90 47.63
4 2003 INDIRETA Automatica 8.92 47.72
5 2003 INDIRETA Nao_Automatica 0.87 4.65
6 2004 DIRETA Nao_Automatica 11.66 48.25
7 2004 INDIRETA Automatica 10.60 43.88
8 2004 INDIRETA Nao_Automatica 1.90 7.87
9 2005 DIRETA Nao_Automatica 14.24 46.52
10 2005 INDIRETA Automatica 13.84 45.21
11 2005 INDIRETA Nao_Automatica 2.53 8.27
12 2006 DIRETA Nao_Automatica 23.94 55.89
13 2006 INDIRETA Automatica 14.82 34.61
14 2006 INDIRETA Nao_Automatica 4.07 9.51
15 2007 DIRETA Nao_Automatica 41.00 56.90
16 2007 INDIRETA Automatica 24.37 33.82
17 2007 INDIRETA Nao_Automatica 6.68 9.28
18 2008 DIRETA Nao_Automatica 35.73 50.52
19 2008 INDIRETA Automatica 29.05 41.08
20 2008 INDIRETA Nao_Automatica 5.94 8.40
21 2009 DIRETA Nao_Automatica 82.70 60.17
22 2009 INDIRETA Automatica 39.45 28.71
23 2009 INDIRETA Nao_Automatica 15.29 11.12
24 2010 DIRETA Nao_Automatica 48.46 42.38
25 2010 INDIRETA Automatica 61.52 53.79
26 2010 INDIRETA Nao_Automatica 4.38 3.83
27 2011 DIRETA Nao_Automatica 62.99 52.95
28 2011 INDIRETA Automatica 51.52 43.31
29 2011 INDIRETA Nao_Automatica 4.46 3.75
30 2012 DIRETA Nao_Automatica 109.92 56.49
31 2012 INDIRETA Automatica 63.92 32.84
32 2012 INDIRETA Nao_Automatica 20.77 10.67
33 2013 DIRETA Nao_Automatica 87.13 52.15
34 2013 INDIRETA Automatica 70.00 41.90
35 2013 INDIRETA Nao_Automatica 9.93 5.94
36 2014 DIRETA Nao_Automatica 69.15 50.32
37 2014 INDIRETA Automatica 60.93 44.34
38 2014 INDIRETA Nao_Automatica 7.34 5.34
39 2015 DIRETA Nao_Automatica 33.04 51.38
40 2015 INDIRETA Automatica 23.26 36.16
41 2015 INDIRETA Nao_Automatica 8.01 12.46
42 2016 DIRETA Nao_Automatica 22.53 54.03
43 2016 INDIRETA Automatica 17.05 40.90
44 2016 INDIRETA Nao_Automatica 2.11 5.07
45 2017 DIRETA Nao_Automatica 27.98 51.73
46 2017 INDIRETA Automatica 21.93 40.56
47 2017 INDIRETA Nao_Automatica 4.17 7.71
48 2018 DIRETA Nao_Automatica 50.04 72.54
49 2018 INDIRETA Automatica 17.41 25.24
50 2018 INDIRETA Nao_Automatica 1.53 2.22
51 2019 DIRETA Nao_Automatica 29.45 71.91
52 2019 INDIRETA Automatica 11.20 27.34
53 2019 INDIRETA Nao_Automatica 0.31 0.75
54 2020 DIRETA Nao_Automatica 37.23 67.80
55 2020 INDIRETA Automatica 16.89 30.76
56 2020 INDIRETA Nao_Automatica 0.79 1.43
57 2021 DIRETA Nao_Automatica 6.04 50.16
58 2021 INDIRETA Automatica 5.94 49.34
59 2021 INDIRETA Nao_Automatica 0.06 0.50

Valores Contratados por Tipo de Operação e Forma de apoio

  • Tipo de Operação: Automática / Não Automática
  • Forma de apoio: Direto/ Indireto
In [65]:
plot_val_contr_oper_apoio(df_consol)

**Avaliação**:

  • As operações DIRETAS sempre são superiores, em valores, com relação às operações INDIRETAS, EXCETO no ano de 2010.
  • As operações INDIRETAS Automaticas sempre são superiores, em valores, com relação às operações INDIRETAS Não Automáticas.

Evolução dos Valores Contratados e Desembolsados por Ano

In [66]:
plot_evol_val_contr_desemb(df_nauto)
plot_evol_val_contr_desemb(df_auto)

Plots: Evolução ao longo dos anos (animados)

Carga e Tratamento dos dados

In [927]:
# Carrega arquivo de PIB por municipio, anos 2002 a 2018
# ---------------------------------------------------------------
print('Carregando dados do PIB...')
pib = pd.read_csv('PIB_Mun_Consolidado.csv', sep='|', decimal=',', encoding='utf-8', low_memory=False)
columns_object = ['CodMun']
for c in columns_object:
    pib[c] = pib[c].astype(int).astype(str)
pib_ano_min = np.min(pib['Ano'])
pib_ano_max = np.max(pib['Ano'])    
print('  - Registros do PIB nos anos de %d a %d: %s' %(pib_ano_min, pib_ano_max, pib.shape[0]))    

# Junta dados do IBGE (Pop2013) ao df de dados do PIB    
# ---------------------------------------------------------------
print('Dados do IBGE (População) adicionados aos dados do PIB...')
pib_pop = pd.merge(pib, ibge[['SIGLA_UF','COD_IBGE', 'POP2013','CAPITAL']], 
                          left_on=['UF','CodMun'], right_on=['SIGLA_UF','COD_IBGE'], how='left', indicator=True)
print('  - Registros do PIB que foram atualizados com dados do IBGE: ', pib_pop[pib_pop['_merge']=='both'].shape[0])
#display(pib_pop['_merge'].value_counts())
del pib_pop['_merge'] 


#Faixas População
faixas_pop = [0, 50000,500000,5000000,10000000,50000000]
pib_pop_faixas = pd.cut(pib_pop['POP2013'], bins=faixas_pop)
pib_pop_faixas_peso = pd.cut(pib_pop['POP2013'], bins=faixas_pop, labels=[50,100,250,500,2500])
pib_pop.insert(17, 'POP2013_Faixa', pib_pop_faixas)
pib_pop.insert(18, 'POP2013_Peso', pib_pop_faixas_peso)
pib_pop['POP2013_log'] = np.log10(pib_pop['POP2013']+0.01)
print('\nPesos e Faixas para dados de população: ')
print('  - Peso: 50 --> Faixa População [0, 50 mil]')
print('  - Peso: 100 --> Faixa População [50 mil, 500 mil]')
print('  - Peso: 250 --> Faixa População [500 mil, 5 milhões]')
print('  - Peso: 500 --> Faixa População [5 milhões, 10 milhões]')    
print('  - Peso: 2500 --> Faixa População Acima 10 milhões')    
print('\nAmostra dos dados de População, com faixa e peso:')
print('Obs. Nos plots, o peso representa a população dos municipios (pontos maiores, municípios mais populosos).')
display(pib_pop.iloc[:,16:20].head(5))


# Junta PIB_pop com df de Contratos por Municipio
# ---------------------------------------------------------------
lista_col_contr = ['ano_contratacao', 'uf', 'municipio_codigo',
                   'Soma_ValorContr','Soma_ValorContr_log', 
                   'Menor_ValorContr', 'Maior_ValorContr','Total_Contr']
pib_contr = pd.merge(pib_pop, df_vlr_ano_mun[lista_col_contr],
                     left_on=['Ano','UF','CodMun'], right_on=['ano_contratacao','uf','municipio_codigo'],  
                     how='left', indicator=True)
num_both = pib_contr[pib_contr['_merge']=='both'].shape[0]
print('Total de registros do dataframe PIB:', pib.shape[0])
print('Total de registros do dataframe de contratos:', df_vlr_ano_mun.shape[0])
print('Total de registros de PIB com dados de Contratos atualizados para cada Ano/ Municipio:', num_both)
print('Percentual de dados preenchidos: %s ' %np.round(num_both/df_vlr_ano_mun.shape[0]*100))
#display(pib_contr['_merge'].value_counts())

# Necessario colocar zero nos contratos 
# municipios com PIB, mas sem investimentos em determinado ano)
# ---------------------------------------------------------------
pib_contr.loc[pib_contr['_merge']=='left_only', ['Soma_ValorContr','Soma_ValorContr_log',\
                                                 'Menor_ValorContr','Maior_ValorContr','Total_Contr']]=0
col_delete = ['ano_contratacao','uf','municipio_codigo']
for c in col_delete:
    del pib_contr[c]

pib_contr = pib_contr.sort_values(by='Ano', ascending=True)
print('\nLista das Regioes: ', pib_contr['Regiao'].unique())

print('\nInformações por Municipio - Colunas do dataframe pib_contr: \n', pib_contr.columns.values)
Carregando dados do PIB...
  - Registros do PIB nos anos de 2002 a 2018: 94616
Dados do IBGE (População) adicionados aos dados do PIB...
  - Registros do PIB que foram atualizados com dados do IBGE:  94616

Pesos e Faixas para dados de população: 
  - Peso: 50 --> Faixa População [0, 50 mil]
  - Peso: 100 --> Faixa População [50 mil, 500 mil]
  - Peso: 250 --> Faixa População [500 mil, 5 milhões]
  - Peso: 500 --> Faixa População [5 milhões, 10 milhões]
  - Peso: 2500 --> Faixa População Acima 10 milhões

Amostra dos dados de População, com faixa e peso:
Obs. Nos plots, o peso representa a população dos municipios (pontos maiores, municípios mais populosos).
POP2013 POP2013_Faixa POP2013_Peso CAPITAL
0 25728 (0, 50000] 50 0
1 101269 (50000, 500000] 100 0
2 6495 (0, 50000] 50 0
3 85863 (50000, 500000] 100 0
4 18041 (0, 50000] 50 0
Total de registros do dataframe PIB: 94616
Total de registros do dataframe de contratos: 70803
Total de registros de PIB com dados de Contratos atualizados para cada Ano/ Municipio: 63524
Percentual de dados preenchidos: 90.0 

Lista das Regioes:  ['Norte' 'Sudeste' 'Sul' 'Centro-oeste' 'Nordeste']

Informações por Municipio - Colunas do dataframe pib_contr: 
 ['Ano' 'Regiao' 'UF' 'NomeUF' 'CodMun' 'NomeMun' 'PIB_Agropecuaria'
 'PIB_Industria' 'PIB_Serv' 'PIB_outras' 'PIB_Areas_total' 'PIB_Imp'
 'PIB_Total' 'PIB_perCapita' 'SIGLA_UF' 'COD_IBGE' 'POP2013'
 'POP2013_Faixa' 'POP2013_Peso' 'CAPITAL' 'POP2013_log' 'Soma_ValorContr'
 'Soma_ValorContr_log' 'Menor_ValorContr' 'Maior_ValorContr' 'Total_Contr'
 '_merge']

Função: Evolução dos Valores Investidos do Municipio

In [937]:
# Parametros
# ---------------------------------------------------------------
'''
    p_Regiao = lista das regioes de interesse
    p_num_mun_UF =  exibir TopN municipios de uma UF (default=1000)
    p_yaxis = variavel socio-demografico no eixo y, para compara-la com os Valores de Investimentos
    df = dataframe com informações socio-demograficas e de Contratos por Municipio
'''

def plot_evol_invest_municipio(df, p_Regiao, p_num_mun_UF, p_yaxis):
    ix = 1
    for R in p_Regiao:
        if ix <= 1:
            pib_contr2 = df.reset_index(drop=True)
            df1 = pib_contr2[pib_contr2['Regiao']==R]
            df1 = df1.groupby(['UF'])['Soma_ValorContr'].nlargest(p_num_mun_UF).reset_index() 
            indices = df1['level_1'].values
            amostra = pib_contr2.iloc[indices]
            amostra = amostra.sort_values(by='Ano')
            
            fig = px.scatter(amostra, x='Soma_ValorContr', y=p_yaxis, size='POP2013_Peso', color='UF', 
                             symbol='CAPITAL', symbol_sequence=['circle','star'], 
                             animation_frame='Ano', animation_group='NomeMun', hover_name='NomeMun',
                             log_x=True, log_y=True, width=1000, height=800,
                             labels=dict(POP2013_Peso='PesoPop',Soma_ValorContr='Valor total dos Contratos no Municipio'),
                             color_discrete_sequence=px.colors.qualitative.Light24)
            
            title = '<i><b>Regiao %s:</b></i>' %R + \
            ' <b>Evolução dos Investimentos com %s do Municipio' %p_yaxis + '</b> <br> \
            Top %s municipios na UF (em valor contratado)' %p_num_mun_UF
            
            fig.update_layout(title_text = title, title_x = 0.5, geo=dict(showframe = False,showcoastlines = True))
            
            fig.update_traces(marker=dict(line=dict(width=1.1,color='DarkSlateGrey')),selector=dict(mode='markers'))
            fig.layout.updatemenus[0].buttons[0].args[1]['frame']['duration'] = 1500
            fig.layout.updatemenus[0].buttons[0].args[1]['transition']['duration'] = 1000
            fig.show()
            
        ix = ix +1
        if ix == 2: 
            ix =1

Plot: Evolução dos Valores Investidos e PIB PerCapita do Municipio

In [940]:
# Parametros
# ---------------------------------------------------------------
p_Regiao = ['Norte', 'Sudeste', 'Sul', 'Centro-oeste', 'Nordeste']
p_num_mun_UF = 1000 # restringe para mostrar TopN municipios de uma UF
p_yaxis = 'PIB_perCapita'

plot_evol_invest_municipio(pib_contr, p_Regiao, p_num_mun_UF, p_yaxis)

Plot: Evolução dos Valores Investidos e PIB_Agronegocio do Municipio

In [944]:
# Parametros
# ---------------------------------------------------------------
p_Regiao = ['Norte', 'Sudeste', 'Sul', 'Centro-oeste', 'Nordeste']
p_num_mun_UF = 1000 # restringe para mostrar TopN municipios de uma UF
p_yaxis = 'PIB_Agropecuaria'

plot_evol_invest_municipio(pib_contr, p_Regiao, p_num_mun_UF, p_yaxis)

Plot: Evolução dos Valores Investidos e PIB_Industria do Municipio

In [942]:
# Parametros
# ---------------------------------------------------------------
p_Regiao = ['Norte', 'Sudeste', 'Sul', 'Centro-oeste', 'Nordeste']
p_num_mun_UF = 1000 # restringe para mostrar TopN municipios de uma UF
p_yaxis = 'PIB_Industria'

plot_evol_invest_municipio(pib_contr, p_Regiao, p_num_mun_UF, p_yaxis)

Plot: Evolução dos Valores Investidos e PIB_Serv do Municipio

In [933]:
# Parametros
# ---------------------------------------------------------------
p_Regiao = ['Norte', 'Sudeste', 'Sul', 'Centro-oeste', 'Nordeste']
p_num_mun_UF = 1000 # restringe para mostrar TopN municipios de uma UF
p_yaxis = 'PIB_Serv'

plot_evol_invest_municipio(pib_contr, p_Regiao, p_num_mun_UF, p_yaxis)